home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS in a Box 7
/
BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso
/
Files
/
Prog
/
M
/
MacStarter.cpt
/
applicationProcs.c
< prev
next >
Wrap
Text File
|
1992-10-11
|
27KB
|
525 lines
/* MacStarter is a shell for simple Macintosh applications shell written in
THINK C, with some small use of its object-oriented features.
This file is the place to start when you want to write a new application
with MacStarter. The whole system is described in a README file that
should be in the same folder with this file. There should also be
sample applicationProc files (kaleidoSketch.c, pentominos.c and
simpleScroll.c). Finally, the file uncommentedProcs.c is a copy
of this file without any comments, in case you would rather use that
as a starting point.
To write an application, you need to fill in or modify at least some
of the functions in this file. (You should start by copying and renaming
the file.) The places in the file where you might need to do some work
are all commented with comments beginning with //. Most of them are
also in the "mark menu" that you see when you hold down the command key
and press the mouse in the title bar of this window.
*/
#include "globals-MacStarter.h"
long gEventWaitTime = 1000000; // This is used by function WaitNextEvent in the
// main program as the maximum acceptable time for the program to
// be "put to sleep" while waiting for the next event. If your
// program has an "ApplicationIdle" function, you will need to
// change this value. See the comment on that function. Otherwise,
// you can ignore gEventWaitTime.
MenuHandle editMenu, fileMenu; // These variables are defined to provide a
// way to refer to the file and edit menus in function UpdataMenus.
// If you add other menus, you will need to define MenuHandles for
// them.
void InitApplication(void); // This is a list of the functions
void UpdateMenus(void); // defined in this file. (I have to
void DoEditMenu(int itemNum); // declare functions before
void DoFileMenu(int itemNum, int* done); // defining them because I turned
void DoOtherMenu(int menuID, int itemNum); // on the "Require Prototypes"
void ApplicationIdle(void); // option in the Language Settings
void CleanUpApplication(void); // panel of the Options dialog.)
void AboutBox(void);
void DoNewCommand(void);
/*********************** Window definition **********************************/
class myWindow : public xWindow {
// The class xWindow is defined in globals-MacStarter.c. It provides the
// basic functionality of Macintosh windows. You define the behaviour of
// actual windows in your program by defining the subclass myWindow of
// class xWindow. To do this, you just have to say how your window
// responds to certain events, by filling in the definitions of the
// functions that are called in response to those events. The list
// of functions that you might have to change is given in this
// "subclass declaration" for myWindow. The actual functions follow.
// See the individual functions for more information.
// You will almost certainly need to add some information to this
// definition of myWindow. You should insert here the
// declarations of any variables you need to hold data relevant
// to the contents of the window. These variables should be defined
// HERE, not as global variables, since each window needs its own
// version of the variables. You can also add new functions to the
// following list of functions. (NOTE: You can certainly define
// additional window classes, if your program needs windows with a
// variety of behaviours.)
public:
virtual void OpenInRect(Str255 title, int left, int top, int right, int bottom);
virtual short Close(void);
protected: // (Note: You will never actually CALL these functions directly;
// just define what they do.)
virtual void SetDefaults(void);
virtual void doKey(char ch);
virtual void doContentClick(Point localPt);
virtual void adjustToNewSize(void);
virtual void doRedraw(Rect* badRect);
virtual void doHScroll(int dh);
virtual void doVScroll(int dv);
virtual void doActivate(int active);
};
// Function SetDefaults is called automatically when a new window is opened,
// BEFORE the actual window is created. It sets up the appearance of the
// window and initializes variables associated with the window. This function
// should always START by calling inherited::SetDefaults, which sets up the
// default appearance and behaviour. THEN, you can make any changes you
// want.
// The inherited function gives default values to the variables
// features, topScrollOffset, bottomScrollOffset, leftScrollOffset,
// rightScrollOffset, minH, minV, maxH, maxV, hLinesPerPage and
// vLinesPerPage. The most important of these is FEATURES, which
// determines whether or not the window has a go-away box, a zoom box,
// a grow box, a horizontal scroll bar, and a vertical scroll bar. Its
// default value is hasGoAway + hasZoom + hasGrow + hasHScroll + hasVScroll,
// which will produce a window with all possible features. If you want
// only a subset of features, you should set the value of features
// appropriately. For example, features = hasGoAway will produce a
// non-resizable, unscrollable window with a go-away box in the upper left
// corner that the user can click on to close the window.
// You will probably not need to worry about the other varaibles,
// but, for the record: minH, minV, maxH and maxV determine how big
// and how small the user can make the window by dragging the grow box in
// the lower right corner of the window. The defaults allow very large and
// very small values. The range of allowable horizontal sizes for the window is
// from minH to maxH, and for vertical sizes is minV to maxV. You might well
// want to change minH and minV to prevent really small windows. You
// can set minH to have the same value as maxH. In that case, the window
// can only be resized vertically. (But be sure that the window is first
// opened at the correct size!) If your window has a maximum size, it should
// not have a zoom box, since zooming will not respect the maximum size.
// When a user clicks in the gray region of a scroll bar, the window
// should scroll by a greater amount than when the user clicks in an
// arrow. The variables hLinesPerPage and vLinesPerPage control this
// behaviour. By definition, a click in the gray area of the horizontal scroll
// bar is equivalent to hLinesPerPage clicks on one of the horizontal scroll's
// arrows. Similarly for vLinesPerPage. Usually, the correct values
// for these variables depend on the size of the window, so they would
// ordinarily be reset in function adjustToNewSize().
// By default, the window's scroll bars will extend all the way across,
// or up and down, the window. Sometimes, you might want to leave some
// space at one end or another of a scroll bar. If so, you can set
// the value of one of the variables topScrollOffset, bottomScrollOffset,
// leftScrollOffset or rightScrollOffset. These work in what should be
// a obvious way.
void myWindow::SetDefaults(void) {
inherited::SetDefaults();
// Make changes to defaults. You also can initialize the window's data.
// Most likely change is erase some of the items on the right of:
// features = hasHScroll + hasVScroll + hasGoAway + hasZoom + hasGrow;
}
// Function OpenInRect is called whenever a window needs to be opened. It should
// start by calling the default inherited::OpenInRect, which actually opens
// the window (including calling SetDefaults in turn). After this, you can
// do any further initialization your window might need. (Most initialization
// can be done in SetDefaults, but when SetDefaults is called, the actual
// window doesn't exist yet. In some cases, such as installing a TEdit or
// a Control, you need the actual window. These things can be done in the
// function below, after the call to inherited::OpenInRect. The variable
// that points to the Mac window data structure is called theWindow.)
void myWindow::OpenInRect(Str255 title, int left, int top, int right, int bottom) {
inherited::OpenInRect(title,left,top,right,bottom);
// insert any additional initialization of window data here.
}
// Function myWindow::Close is called when the window is closing (for example,
// when the user clicks in its GoAway box). If you have any dynamically allocated
// variables in the window, this is the place to delete their storage.
// It is ESSENTIAL that the call to inherited::Close be the LAST thing in
// this function. (This function is declared to return a short in case you
// want a Close function that can "refuse to close" by returning a value
// of zero. Typically, you might ask if the user wants to save the window
// contents before closing, and you might provide a CANCEL option that
// should abort the closing. If the window is closing because the user
// chose QUIT from the file menu, you will need to know that the user
// decided to cancel. You could then call the close function like this:
// if ( win->Close() ) ... )
short myWindow::Close(void) {
// Clean-up before closing window.
inherited::Close(); // You can't refer to any window data after this call !
return 1; // not used in the existing program
}
// Function doKey is called when the user types any character. The character
// typed is passed as the parameter ch. If you want to get at the actual
// event record that generated this function call, you can find it in the
// global variable gEvent. You can, for example, check whether the user
// was holding down the option key by checking:
// if ( gEvent.modifiers & optionKey ) ... Note that command key events
// are NOT sent to this function. They are automatically intercepted and
// changed into menu events.
// NOTE: Before this function is called, the "graphics port" is set to
// this window. That just means that ANY drawing you do in this function
// will apply to this window.
void myWindow::doKey(char ch) {
// Handle key-click
}
// Function doContentClick is called when your program needs to respond to
// a user clicking the mouse on this widow. (Clicks on scroll bars, grow
// boxes, etc, are handled automatically and are NOT sent to this function.
// Also, when the user clicks on an inactive window, that click is handled
// by activating the window and is NOT sent to this function.) The coordinates
// of the point where the user clicked are sent in the parameter localPt.
// These coordinates are in the window's local coordinates (in which the
// top, left corner is (0,0) unless you have changed them). You can get
// full information about the mouse-down event from the global variable
// gEvent. For example, "if (gEvent.modifiers & cmdKey)..." will test
// whether the user was holding down the command key when the mouse was clicked.
// In addition, the global variable gClickCount can be used to determine
// whether this is a double click; this variable is set to 1 for a single
// click, to 2 for the second click of a double click, to 3 for the third
// click of a triple click, etc. For a double click, for example, this function
// gets BOTH clicks in succession, with gClickCount set to 1 the first
// time and to 2 the second time. (Also NOTE: The Macintosh toolbox function
// StillDown() will be true as long as the user continues to hold down the
// mouse key. You might, for example, use a while (StillDown()) loop to
// follow the mouse or perform some action as long as the user holds down
// the button.)
// NOTE: Before this function is called, the "graphics port" is set to
// this window. That just means that ANY drawing you do in this function
// will apply to this window.
void myWindow::doContentClick(Point localPt) {
// Handle a mouse click
}
// Function doRedraw is called when the window, or a portion of it, needs to
// be redrawn (because the window has been resized or moved from behind
// another window, for example.) It is also called when the window is
// first opened (after all the initialization done in SetDefaults and
// OpenInRect). Note that your window always needs to save enough data
// to redraw itself (if you want your application to act like a real Mac program).
// Ordinarily, you will simply redraw the entire contents of the window.
// However, if your window is very complicated, you might save some time
// by using the parameter badRect. This is a rectangle that contains the
// portion of the window that actually needs to be redrawn.
// If your window uses scroll bars, you will need to know the current
// settings and maximums on those scroll bars. You can find out by
// calling the functions GetHVal(), GetVVal(), GetHMax() and GetVMax().
// (People sometimes have trouble understanding this function. It has to
// exist because the Mac doesn't actually remember what's in your window.
// When one window covers another, anything in the bottom window is forgotten
// When the window is later uncovered, the Mac sticks you with the
// responsibility of remembering what was there and reconstituting it.
// So, ordinarily, this function is redoing old work rather than getting
// new work done. This imposes the great burden on the programmer of
// remembering what's in each window.)
// NOTE: Before this function is called, the "graphics port" is set to
// this window. That just means that ANY drawing you do in this function
// will apply to this window.
void myWindow::doRedraw(Rect* badRect){
// redraw current contents of window.
}
// Function adjustToNewSize is called whenever the window changes size because
// the user drags its grow box or clicks its zoom box. If you need to make
// any changes to accomodate the new size, do it here. However, DO NOT
// redraw the window here; function doRedraw() is going to be called
// automatically after this function to do the actual redrawing.
// The inherited function simply resizes and moves the scroll bars, if any.
// After this, you might need to readjust the values, maximums or
// linesPerPage associated with the scroll bars. The functions SetHVal(),
// SetVVal(), SetHMax(), SetVMax(), SetHLinesPerPage() and SetVLinesPerPage()
// can be used to change these settings. If you have TEdits or
// controls of your own, they will have to be resized and moved. If the
// stuff drawn in the window needs to be scaled to the new size, you can do
// it here.
void myWindow::adjustToNewSize(void) {
inherited::adjustToNewSize();
// respond to change in window size
}
// Function doHScroll is called when the user changes the position of the
// horizontal scroll. It will be called repeatedly if the user holds down the
// mouse button on an arrow or in the gray area of the scroll. The inherited
// function simply erases the sreen and then calls your DoRedraw() function
// to redraw the screen contents (presumably reflecting the new position of
// the scroll). Depending on your application, this might be fine, but it
// can cause an annoying flicker and can be too time-consuming. If you
// want to change this, you should ERASE the call to inherited::doHScroll
// and substitute your own code. (Typically, you will call the Mac
// Toolbox routine ScrollRect() and then just do the minimal redrawing
// necessary.) The parameter tells the CHANGE in the value of the horizontal
// scroll. You can get the actual new value by calling GetHVal().
void myWindow::doHScroll(int dh) {
inherited::doHScroll(dh); // replace with your own code if you
// don't like the default behaviour
}
// Function doVScroll is called when the user changes the position of the
// vertical scroll. Similar comments to those on doHScroll() apply.
void myWindow::doVScroll(int dv) {
inherited::doVScroll(dv); // replace with your own code if you
// don't like the default behaviour
}
// Function doActivate is called when your window is deactivated (because
// the user clicks on another window) or activated (because the user clicks
// on this window and it is being moved to the front). The inherited
// function takes care of activating or deactivating the scroll bars. If
// your window has its own control or TEdit, you can activate or deactivate
// them here. Otherwise, there is probably nothing that this function
// needs to do. (In particular, this function does NOT redraw the window.)
// The parameter "active" is 0 if the window is being deactivated and is
// non-zero if it is being activated.
void myWindow::doActivate(int active) {
inherited::doActivate(active);
// activate/deactivate controls, TEdits, etc. (if any)
}
/****************************************************************************/
// Function InitApplication is called when the application first starts up.
// It should be used to initialize any global variables that require
// initialization. Here, it is also used to open the first window
// of the program.
void InitApplication(void) {
MenuHandle appleMenu;
fileMenu = GetMHandle(2); // get handles to the menus, for use in UpdateMenus
editMenu = GetMHandle(3);
appleMenu = GetMHandle(1); // Note that your program is not responsible for
// managing the apple menu, except to set the
// program name in the first line of the
// menu, as is done in the next line.
SetItem(appleMenu,1,"\pAbout Generic...");
DoNewCommand(); // opens a window.
}
// Function UpdateMenus() is called just before any user action directed at the
// menu bar is processed. That is, it is called when the user clicks in
// the menu bar (but before the user sees any menus), or when the user
// command-presses a keyboard key (but before that command is looked up
// in the menus). The purpose of this function is to enable and
// disable commands as appropriate. A command that is "disabled" is
// grayed out in the menu and is unavaialble to the user. For example,
// if there is no window open, then the Close Window command should
// certainly be disabled. The function UpdateMenus should set the
// enable/disable status of any menu item whose status can change.
// (In the existing program's file menu, for example, the New and
// Quit commands are always enabled. The Close command is enabled and
// disabled as appropriate by this function.)
// The Edit menu is a special case. This menu is supposed to be
// available, with all its standard commands enabled, if the front window
// on the screen belongs to a desk accessory rather than to your program.
// This is handled by the first few lines of the function below, which
// you should not change. You should also not insert new items into
// the edit menu, except at the end, after the standard items.
void UpdateMenus(void) {
short i;
WindowPtr win; // pointer to macintosh window data structure
xWindow *xwin; // pointer to xWindow data structure
win = FrontWindow(); // this is the front window on the screen
if ( win && ((WindowPeek)win)->windowKind < 0 ) { // Desk accessory window
EnableItem(editMenu,1); // Do not change this section.
for (i=3; i<7; i++) // This has nothing to do with
EnableItem(editMenu,i); // your program
}
else { // enable/disable edit item menus as relevant to your program
DisableItem(editMenu,1);
for (i=3; i<7; i++) // Here, I just disable them all
DisableItem(editMenu,i);
}
if (win && xWindow::Window2XWindow(win,&xwin)) { //if front window is mine...
EnableItem(fileMenu,2); // enable Close command
}
else {
DisableItem(fileMenu,2); // disable Close command
}
}
// Function DoEditMenu is called if the user selects a command from the
// Edit menu. (By default, these commands are disabled, so this function
// won't be called unless you enable them in function UpdateMenus().)
// The parameter gives the item number of the command, counting from the
// top of the menu.
void DoEditMenu(int itemNum) {
// handle command from edit menu
}
// Function DoFileMenu() is called if the user selects a command from the
// File menu. The parameter itemNum gives the number of the command counting
// down from the top of the menu. NOTE that if you insert items into the
// menu, the command numbers for the existing commands will change, and these
// changes will have to be reflected in the if statements in this function.
// The parameter "done" should be set to 1 if the user chooses QUIT from the
// file menu; however, you have the possibility of ABORTING this command
// simply by not setting this value. (For example, you might as the user
// if she wants to save her data before quitting and she might click on the
// cancel button in the dialog box.)
void DoFileMenu(int itemNum, int* done) {
xWindow *win;
// Handle file menu commands:
if (itemNum == 4)
*done = 1;
else if (itemNum == 1)
DoNewCommand();
else if (itemNum == 2 && xWindow::Window2XWindow(FrontWindow(),&win))
win->Close();
}
// If you have added other menus besides the Apple, File and Edit menus,
// this function will be called when the user chooses a command from
// such a menu. The parameters tell you the menu and the number of the
// item in the menu. Note that the first parameter is the menuID,
// NOT the position of the menu in the menu bar. (If the menu comes out
// of a resource file, the menuID is the resource number; if you create it
// "on the fly", you set the menuID when you create it.)
void DoOtherMenu(int menuID, int itemNum) {
// handle command (from menu other than apple, file or edit menu)
}
// Function ApplicationIdle is called periodically while your program is
// running. Specifically, it is called each time an "event" is generated
// by the user or by the operating system. User events include mouse and
// key clicks. Operating system events are things like window-activation
// events. In addition, if no other event occurs, the operating system
// can send a "null" event. The purpose of such an event is exactly to
// make sure that a function like ApplicationIdle gets called sufficiently
// often. The frequency of null events is determined by the global
// varialble gEventWaitTime. If you put anything into this function,
// you should change the value of this variable at the top of this
// file. gEventWaitTime is measured in 1/60-ths of a second. It represents
// the maximum time that you would like between calls to ApplicationIdle.
// (It is not a guaranteed that the operating system will always be able to
// meet this deadline; it depends on what else is going on in the system.)
// One common use of ApplicationIdle is to set the cursor style to reflect
// the part of the screen that the mouse is currently over. If you do this,
// a value of gEventWaitTime of about 3 seems to work well.
// Another use is to allow the null events to "drive" a long computation
// or an animation. If you just go ahead and do an animation, say, with a
// long for loop, there will be no way for the user to interrupt it. It is
// better to use ApplicationIdle to do just one frame of an animation or
// one small piece of a computation. Of course, this is much more difficult--
// you need to keep track of what you are doing in global variables or
// window data variables. Anyway, if you do do this, you should set
// gEventWaitTime to 0. This just asks the operating system to spend
// as little time as possible away from your program.
// If your program uses a TEdit (This is a standard Mac text edit box),
// Then you should call TEIdle in this function and set gEventwaitTime
// to a value no greater than about 10.
// The reason for not automatically setting gEventWaitTime to a small
// value is that the operating system can give time to other programs
// running in the background if there is nothing for your program to do.
void ApplicationIdle(void) {
// Perform any periodic task required by your program
}
// Function CleanUpApplication is called just before the program ends normally.
// You will probably have nothing to do here, especially since there is
// no way to abort the program termination, but, just in case...
void CleanUpApplication(void) {
}
// Function AboutBox is called when the user chooses the first item in the
// Apple menu, usually a command of the form "About <program-name>...".
// It should display information about your program. This default
// version simply displays a box that has four fill-in-the-blank areas
// that are set by the call to ParamText(). You can just make changes
// to this. However, if you happen to use this shell to write a serious
// program, you will want to do something different. For one thing, this
// method is totally insecure. Since it just uses one of the resources in
// the resource file MacStarter.π.rsrc, anyone who wanted to steal credit
// for your program could do so by editing its resource fork with ResEdit.
// (It would be better to open a window and draw into it directly.)
// Note: The \r's in the third line here represent line breaks. There
// is room for three fairly short lines in this field, which is meant for
// your address (although, of course, you can use it for whatever you want).
void AboutBox(void) {
// Set up program name, author name, address, short program description.
ParamText( "\pGeneric Application",
"\pDavid Eck",
"\pHobart and William Smith College\rGeneva, NY 14456\rE-mail: eck@hws.bitnet",
"\pThis program can be used as a shell for creating Macintosh Applications.");
Alert(128,0L);
}
// Function DoNewCommand is called from DoFileMenu above when the user chooses
// the New command from the file menu. In this sample program, it is also
// called when the program is first started up. It simply creates
// and opens a window. Here, win->Open(title) will open a window that is
// about 3/4 the size of the screen in each dimension. Each successive
// window will be slightly offset from the previous one. You could also
// open the window with win->OpenFullScreen(title), which will open a window
// that fills the entire screen. Or, win->OpenInRect(title,L,t,r,b) will
// open a window in a specified rectangle. In this case, the window extends
// from L to r horizontally and from t to b vertically. L, t, r and b are
// measured in screen coordinates, in which the top left corner of the
// screen is (0,0). (Actually, L, t, r, and b specify the position of the
// inside of the window only, not including the title bar or a 1-pixel border
// around the window.)
void DoNewCommand(void) {
myWindow *win;
win = new myWindow; // (this create window storage space before opening it)
win->Open("\pSample Window"); // need a better window title!
}